using System;
using System.Collections.Generic;
using System.Linq;
using Pay.DTO;
using Pay.IService;
using Pay.Data;
using System.Linq.Expressions;
using Pay.Service.Cache;
using Pay.Core;

namespace Pay.Service {
	public class RegionService : ServiceBase, IRegionService, IDisposable {
		private IUnitOfWork _iUnitOfWork;

		public RegionService(IUnitOfWork iUnitOfWork) : base(iUnitOfWork) {
			_iUnitOfWork = iUnitOfWork;
		}

		public IEnumerable<region_dto> Get() {
			return context.Regions.FromCache<Region, region_dto>("Regions");
		}

        public IEnumerable<region_dto> Gets() {
            //return context.Regions.ForEach(regions => {

            //});
            return null;
        }

        /// <summary>
        /// 查询子类、将子类放在children中
        /// </summary>
        /// <returns>The all.</returns>
        /// <param name="sort">排序：0省按id,1省到首字母</param>
        /// <param name="read_depth">读到哪一层</param>
        /// <param name="filer_txah">过滤港澳台海外</param>
        public IEnumerable<region_dto> GetAll(int sort = 0, int read_depth = -1, bool filer_txah = true) {
			IQueryable<Region> query = context.Regions;
			if (read_depth != -1) query = query.Where(c => c.Depth <= read_depth);
			if (filer_txah) query = query.Where(c => c.Id != 820000 && c.Id != 990000
									   && c.Id != 710000 && c.Id != 810000);
			if (sort == 0)
				query = query.OrderBy(c => c.Id);
			else
				query = query.OrderBy(c => c.FirstLetter).ThenBy(c => c.Id);

			return query.FromCacheFirstOrDefault((IQueryable<Region> query2) => {
				var list = query2.ProjectTo<Region, region_dto>();
				IEnumerable<region_dto> dto = list.Where(c => c.parent_id == 0).ToList();
				getChilds(list, dto);
				return dto;
			}, "Regions");
		}
		private void getChilds(IEnumerable<region_dto> list, IEnumerable<region_dto> child) {
			foreach (var item in child) {
				var c1 = list.Where(c => c.parent_id == item.id).ToList();
				item.children = c1;
				if (c1.Count > 0)
					getChilds(list, c1);
			}
		}

		/// <summary>
		/// 查询区域的所有上级（N），包括本身
		/// </summary>
		/// <param name="id"></param>
		/// <returns></returns>
		public IEnumerable<region_dto> GetParents(long id) {
			var member = Get(id);
			if (string.IsNullOrEmpty(member.path))
				return new List<region_dto> { member };

			var path = member.path.Split('-').Select(c => long.Parse(c));
			return context.Regions.Where(c => path.Any(pid => pid == c.Id) || c.Id == id).FromCache<Region, region_dto>("Regions");
		}

		/// <summary>
		/// 查询子类
		/// </summary>
		/// <param name="id"></param>
		/// <returns></returns>
		public IEnumerable<region_dto> GetByParentId(long id) {
			Expression<Func<Region, bool>> filter = c => c.ParentId == id;
			return context.Regions.Where(filter).OrderBy(c => c.Sort).FromCache<Region, region_dto>("Regions");
		}

		public region_dto Get(long id) {
			return context.Regions.FirstOrDefault(c => c.Id == id).ToDtoObject<region_dto>();
		}

		public IEnumerable<region_dto> Get(IEnumerable<long> ids) {
			Expression<Func<Region, bool>> filter = c => ids.Any(id => c.Id == id);
			return context.Regions.Where(filter).OrderBy(c => c.Sort).FromCache<Region, region_dto>("Regions");
		}

		/// <summary>
		/// 查询省市区id
		/// </summary>
		/// <param name="region_id"></param>
		/// <returns></returns>
		public long[] GetRegionIds(long region_id) {
			var item = Get(region_id);
			long[] result = new long[3] { 0, 0, 0 };
			if (item != null) {
				if (!string.IsNullOrEmpty(item.path)) {
					var path = item.path.Split('-').Select(c => long.Parse(c)).ToList();
					if (path.Count == 2) {
						result[0] = path[0];
						result[1] = path[1];
						result[2] = region_id;
					} else {
						result[0] = path[0];
						result[1] = region_id;
					}
				} else
					result[0] = region_id;
			}
			return result;
		}

		public string GetRegionNames(long region_id) {
			var item = Get(region_id);
			return item.region_name;
		}

		//var replace_to = "汉族,壮族,满族,回族,苗族,维吾尔族,土家族,彝族,蒙古族,藏族,布依族,侗族,瑶族,朝鲜族,白族,哈尼族,哈萨克族,黎族,傣族,畲族,傈僳族,仡佬族,东乡族,高山族,拉祜族,水族,佤族,纳西族,羌族,土族,仫佬族,锡伯族,柯尔克孜族,达斡尔族,景颇族,毛南族,撒拉族,布朗族,塔吉克族,阿昌族,普米族,鄂温克族,怒族,京族,基诺族,德昂族,保安族,俄罗斯族,裕固族,乌孜别克族,门巴族,鄂伦春族,独龙族,塔塔尔族,赫哲族,珞巴族,自治县,自治区,自治州,地区".Split(',');
		public int Add(region_dto dto) {
			var model = dto.ToDtoObject<Region>();
			if (model.ParentId == 0) {
				model.Depth = 1;
				model.Path = string.Empty;
				model.RegionName = model.Name;
			} else {
				var parent = context.Regions.FindById(model.ParentId);
				model.Depth = parent.Depth + 1;
				model.Path = string.IsNullOrEmpty(parent.Path) ? parent.Id.ToString() : string.Format("{0}-{1}", parent.Path, parent.Id);
				model.RegionName = string.Format("{0} {1}", parent.RegionName, model.Name);
			}
			model.Sort = GetByParentId(model.ParentId).Count() + 1;
			context.Regions.Add(model);
			int result = _iUnitOfWork.Commit("Regions");
			return result;
		}

		public int Add(List<region_dto> dto) {
			var list = dto.ToDtoList<Region>();
			foreach (var model in list) {
				if (model.ParentId == 0) {
					model.Depth = 1;
					model.Path = string.Empty;
					model.RegionName = model.Name;
				} else {
					var parent = list.FirstOrDefault(c => c.Id == model.ParentId);
					model.Depth = parent.Depth + 1;
					model.Path = string.IsNullOrEmpty(parent.Path) ? parent.Id.ToString() : string.Format("{0}-{1}", parent.Path, parent.Id);
					model.RegionName = string.Format("{0} {1}", parent.RegionName, model.Name);
				}
				context.Regions.Add(model);
			}
			int result = _iUnitOfWork.Commit("Regions");
			return result;
		}

		public int Update(region_dto dto) {
			if (dto.id == dto.parent_id)
				throw new ServerErrorException("上级不能是本身");
			var model = context.Regions.FindById(dto.id);
			var old_depth = model.Depth;
			string old_path = string.IsNullOrEmpty(model.Path) ? string.Empty : string.Format("-{0}-", model.Path);
			bool unchanged_Parent = dto.parent_id == model.ParentId;
			dto.ToDtoObject<Region>(model);

			if (!unchanged_Parent) {
				if (model.ParentId == 0) {
					model.Depth = 1;
					model.Path = string.Empty;
				} else {
					var parent = context.Regions.FindById(model.ParentId);
					if (parent == null)
						throw new ServerErrorException("找不到上级");
					if (string.Format("-{0}-", parent.Path).Contains(string.Format("-{0}-", model.Id)))
						throw new ServerErrorException(string.Format("{0}原来是{1}的下级，不能调整", parent.Name, model.Name));
					model.Depth = parent.Depth + 1;
					model.Path = string.IsNullOrEmpty(parent.Path) ? parent.Id.ToString() : string.Format("{0}-{1}", parent.Path, parent.Id);
					model.FullName = string.IsNullOrEmpty(parent.Path) ? parent.Name.ToString() : string.Format("{0} {1}", parent.FullName, parent.Name);
				}
				//修改下级的Path
				var childs = (from item in context.Regions
							  where ("-" + item.Path + "-").Contains("-" + model.Id + "-")
							  select item).ToList();
				foreach (var child in childs) {
					if (old_depth > model.Depth) {
						//升级,更新数据的新path是空时，子集的旧path用-换，否则旧path换更新数据的新path
						bool is_frist = string.IsNullOrEmpty(model.Path);
						child.Path = string.Format("-{0}-", child.Path).Replace(old_path, is_frist ? "-" : string.Format("-{0}-", model.Path)).Trim('-');
					} else if (old_depth == model.Depth) {
						//平移,用旧path换新path
						child.Path = string.Format("-{0}-", child.Path).Replace(old_path, string.Format("-{0}-", model.Path)).Trim('-');
					} else {
						//降级，更新数据的旧path是空时时，子集的旧path前加更新数据的新path
						if (string.IsNullOrEmpty(old_path))
							child.Path = model.Path + "-" + child.Path;
						else
							child.Path = string.Format("-{0}-", child.Path).Replace(old_path, string.Format("-{0}-", model.Path)).Trim('-');
					}
					child.Depth = child.Path.Split('-').Length + 1;
				}
			}

			int result = _iUnitOfWork.Commit("Regions");
			return result;
		}

		public int Delete(long id) {
			if (GetByParentId(id).Count() > 0)
				throw new ServerErrorException("有下级不可以删除");
			context.Regions.Remove(id);
			int result = _iUnitOfWork.Commit("Regions");
			return result;
		}
		public void ExportAreaCode(string areaName, string areaCode) {
			var region = context.Regions.FirstOrDefault(c => c.Name == areaName);
			if (region != null) {
				region.AreaCode = areaCode;
			}
			_iUnitOfWork.Commit("Regions");
		}
		public string GetAreaCode(string region_name) {
			var region = context.Regions.FirstOrDefault(c=>c.RegionName == region_name);
			return (region != null ? region.AreaCode : "");
		}
	}
}
